﻿#ifndef BIN_TO_CSV_H
#define BIN_TO_CSV_H
#include "csvData.h"
#include "crc.h"
#include "csvProcessApi.h"
#include "Bytes2Short.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#include "ThreadPool.h"

#pragma pack(push, 1)
typedef struct _Channel9Data_T
{
    uint8_t vehicleType;        // 8-bit unsigned integer
    uint8_t vehTotalMileage;    // 8-bit unsigned integer
    uint16_t vehSpd;            // 16-bit unsigned integer
    uint8_t rainLevel;          // 8-bit unsigned integer
    uint8_t guard;              // 8-bit unsigned integer
    uint8_t reserved;           // 8-bit unsigned integer
    uint8_t year;               // 8-bit unsigned integer
    uint8_t month;              // 8-bit unsigned integer
    uint8_t date;               // 8-bit unsigned integer
    uint8_t hour;               // 8-bit unsigned integer
    uint8_t min;                // 8-bit unsigned integer
    uint8_t sec;                // 8-bit unsigned integer
    uint16_t ms;                // 16-bit unsigned integer
    uint8_t crashchl;           // 8-bit unsigned integer
    uint8_t crashshts;          // 8-bit unsigned integer
    uint8_t PonyVehicleID[8];   // Array of 8-bit unsigned integers, length 8
    uint8_t Swversion[3];       // Array of 8-bit unsigned integers, length 3
    uint8_t Algversion[3];      // Array of 8-bit unsigned integers, length 3
    uint8_t communication_err;  // 8-bit unsigned integer
    uint8_t system_err;         // 8-bit unsigned integer
    uint8_t config_err;         // 8-bit unsigned integer
    uint16_t chl0crashstrength; // 16-bit unsigned integer
    uint16_t chl1crashstrength; // 16-bit unsigned integer
    uint16_t chl2crashstrength; // 16-bit unsigned integer
    uint16_t chl3crashstrength; // 16-bit unsigned integer
    uint16_t chl4crashstrength; // 16-bit unsigned integer
    uint16_t chl5crashstrength; // 16-bit unsigned integer
    uint16_t chl6crashstrength; // 16-bit unsigned integer
    uint16_t chl7crashstrength; // 16-bit unsigned integer
    uint16_t capvalue;          // 16-bit unsigned integer
} Channel9Data_T;
#pragma pack(pop)

const size_t PACKET_SIZE = 8384;
const size_t DATA_SIZE = 8244;
const size_t HEADER_SIZE = 3;
const uint8_t HEADER[3] = {0x00, 0x34, 0x20};

static std::string csvPath;
static std::string csvPath1;

static std::string strFileName1 = ""; // 当前组基准
static std::string strFileName3 = ""; // 上一个文件名
static int duplicateCount = 0;        // 当前组内重复计数
static std::ofstream csvFile;
static int iCSVCont = 0;
#define DATA_POINTS_PER_COLUMN 512
#define NUM_COLUMNS 8
#define CHANNEL9_SIZE sizeof(Channel9Data_T)

CSV_API void binToCsv(const std::string& binFilename, const std::string& csvFilename)
{
    std::ifstream binFile(binFilename, std::ios::binary);
    std::ofstream csvFile(csvFilename);
    if (!binFile || !csvFile) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    csvFile << "Name,Age,Salary\n";

    while (true) {
        int len = 0;
        if (!binFile.read(reinterpret_cast<char*>(&len), sizeof(len))) break;

        std::string name(len, '\0');
        if (!binFile.read(&name[0], len)) break;

        int age = 0;
        if (!binFile.read(reinterpret_cast<char*>(&age), sizeof(age))) break;

        double salary = 0;
        if (!binFile.read(reinterpret_cast<char*>(&salary), sizeof(salary))) break;

        csvFile << name << "," << age << "," << salary << "\n";
    }

    std::cout << "BIN -> CSV Successed.\n";
}

int parsePacket(const uint8_t* pkt, size_t len, uint8_t* crcData, int &iCrcDataLen, std::vector<uint16_t> &vecCh9, int iPacketIndex);
std::string getCSVFileName(const std::vector<uint16_t> &vecCh9);

uint16_t readUint16LE(const uint8_t* p) 
{
    // 小端转uint16_t
    return static_cast<uint16_t>(p[0]) | (static_cast<uint16_t>(p[1]) << 8);
}

inline uint8_t readUint8(const uint8_t* buf, size_t& offset)
{
    return buf[offset++];
}

inline uint16_t readUint16(const uint8_t* buf, size_t& offset)
{
    uint16_t v = buf[offset] | (buf[offset + 1] << 8); // 小端
    offset += 2;
    return v;
}

uint8_t asciiToDigit(uint8_t ascii) 
{
    if (ascii >= '0' && ascii <= '9') 
    {
        return ascii - '0';   // 转换成数字
    }
    return ascii; // 不是数字，保持原值
}


// ---- 解析函数 ----
// Channel9Data_T parseChannel9Data(uint8_t* buf, size_t startOffset)
// {
//     Channel9Data_T ch9{};
//     size_t offset = startOffset + 2;

//     ch9.vehicleType     = readUint8(buf, offset);
//     ch9.vehTotalMileage = readUint8(buf, offset);
//     ch9.vehSpd          = readUint16(buf, offset);
//     ch9.rainLevel       = readUint8(buf, offset);
//     ch9.guard           = readUint8(buf, offset);
//     ch9.reserved        = readUint8(buf, offset);
//     ch9.year            = readUint8(buf, offset);
//     ch9.month           = readUint8(buf, offset);
//     ch9.date            = readUint8(buf, offset);
//     ch9.hour            = readUint8(buf, offset);
//     ch9.min             = readUint8(buf, offset);
//     ch9.sec             = readUint8(buf, offset);
//     ch9.ms              = readUint16(buf, offset);
//     ch9.crashchl        = readUint8(buf, offset);
//     ch9.crashshts       = readUint8(buf, offset);

//     for (int i = 0; i < 8; i++)  ch9.PonyVehicleID[i] = asciiToDigit(buf[offset++]);
//     for (int i = 0; i < 3; i++)  ch9.Swversion[i]    = asciiToDigit(buf[offset++]);
//     for (int i = 0; i < 3; i++)  ch9.Algversion[i]   = asciiToDigit(buf[offset++]);

//     ch9.communication_err = readUint8(buf, offset);
//     ch9.system_err        = readUint8(buf, offset);
//     ch9.config_err        = readUint8(buf, offset);

//     ch9.chl0crashstrength = readUint16(buf, offset);
//     ch9.chl1crashstrength = readUint16(buf, offset);
//     ch9.chl2crashstrength = readUint16(buf, offset);
//     ch9.chl3crashstrength = readUint16(buf, offset);
//     ch9.chl4crashstrength = readUint16(buf, offset);
//     ch9.chl5crashstrength = readUint16(buf, offset);
//     ch9.chl6crashstrength = readUint16(buf, offset);
//     ch9.chl7crashstrength = readUint16(buf, offset);

//     ch9.capvalue          = readUint16(buf, offset);

//     return ch9;
// }


int parseChannel9Data(std::vector<uint16_t>& vecResult, const uint8_t* buf, int iLength)
{
    if (iLength != CHANNEL9_SIZE) {
        std::cout << "Error: Length:" << iLength
                  << " != Expected:" << CHANNEL9_SIZE << std::endl;
        return -1;
    }

    vecResult.clear();
    vecResult.reserve(41);

    size_t offset = 0;

    auto readUint8 = [&](size_t& ofs) -> uint8_t {
        return buf[ofs++];
    };

    auto readUint16 = [&](size_t& ofs) -> uint16_t {
        uint16_t v = static_cast<uint16_t>(buf[ofs]) | (static_cast<uint16_t>(buf[ofs + 1]) << 8);
        ofs += 2;
        return v;
    };

    auto asciiToDigit = [&](uint8_t c) -> uint8_t {
        return (c >= '0' && c <= '9') ? (c - '0') : c;
    };

    auto push8  = [&](uint8_t v)  { vecResult.push_back(static_cast<uint16_t>(v)); };
    auto push16 = [&](uint16_t v) { vecResult.push_back(v); };

    // --- 开始解析 ---
    push8(readUint8(offset));   // vehicleType
    push8(readUint8(offset));   // vehTotalMileage
    push16(readUint16(offset)); // vehSpd
    push8(readUint8(offset));   // rainLevel
    push8(readUint8(offset));   // guard
    push8(readUint8(offset));   // reserved
    push8(readUint8(offset));   // year
    push8(readUint8(offset));   // month
    push8(readUint8(offset));   // date
    push8(readUint8(offset));   // hour
    push8(readUint8(offset));   // min
    push8(readUint8(offset));   // sec
    push16(readUint16(offset)); // ms
    push8(readUint8(offset));   // crashchl
    push8(readUint8(offset));   // crashshts

    for (int i = 0; i < 8; i++) push8(asciiToDigit(buf[offset++]));
    for (int i = 0; i < 3; i++) push8(asciiToDigit(buf[offset++]));
    for (int i = 0; i < 3; i++) push8(asciiToDigit(buf[offset++]));

    push8(readUint8(offset));   // communication_err
    push8(readUint8(offset));   // system_err
    push8(readUint8(offset));   // config_err

    for (int i = 0; i < 8; i++) push16(readUint16(offset)); // chl crashstrength

    push16(readUint16(offset)); // capvalue

    if (42 == vecResult.size())
    {
        return 0;
    } else {
        return -2;
    }
}

std::string createFileName(const std::string& strFileName, const std::vector<uint16_t> &ch9Values)
{
    if (strFileName1.empty() || strFileName != strFileName1) 
    {
        // 新的分组，重置
        strFileName1 = strFileName;
        strFileName3 = strFileName;
        duplicateCount = 0;
    }
    else 
    {
        // 与当前分组基准相同 → 增加后缀编号
        duplicateCount++;
        std::ostringstream oss;
        oss << "./data/Test/20" 
            << std::setw(2) << std::setfill('0') << ch9Values.at(6)
            << std::setw(2) << std::setfill('0') << ch9Values.at(7)
            << std::setw(2) << std::setfill('0') << ch9Values.at(8)
            << "_" 
            << std::setw(2) << std::setfill('0') << ch9Values.at(9)
            << std::setw(2) << std::setfill('0') << ch9Values.at(10)
            << std::setw(2) << std::setfill('0') << ch9Values.at(11)
            << std::setw(3) << std::setfill('0') << ch9Values.at(12) + duplicateCount
            << ".csv";
        strFileName3 = oss.str();
    }

    return strFileName3;
}

// writeCSV 函数（添加详细错误日志）
int writeCSV(const uint16_t u16data[], int iDataLen, const std::vector<uint16_t> vecCh9)
{
    if (iDataLen != DATA_SIZE) {
        std::cerr << "Failed to Get Data Length: " << iDataLen << std::endl;
        return -1;
    }

    std::string strFileName = getCSVFileName(vecCh9);
    // std::cout << "Get CSV(" << iCSVCont << "): " << strFileName << std::endl;
    std::ofstream csvFile(strFileName, std::ios::out | std::ios::trunc);
    if (!csvFile.is_open()) {
        std::cerr << "Failed to open CSV: " << strFileName << " - Reason: " << std::strerror(errno) << std::endl;
        return -2;
    }

    csvFile << "\"Tunnel-1\",\"Tunnel-2\",\"Tunnel-3\",\"Tunnel-4\","
            << "\"Tunnel-5\",\"Tunnel-6\",\"Tunnel-7\",\"Tunnel-8\",\"Tunnel-9\"\n";

    for (int row = 0; row < 512; row++) {
        for (int col = 0; col < 8; col++) {
            uint16_t val = u16data[col * 512 + row];
            csvFile << val << ",";
        }
        if (row < vecCh9.size()) {
            csvFile << vecCh9[row];
        } else {
            csvFile << 0;
        }
        csvFile << "\n";
    }

    csvFile.close();
    return 0;
}

std::string getCSVFileName(const std::vector<uint16_t> &vecCh9)
{
    std::ostringstream oss;
    oss << "./data/Test/20" 
        << std::setw(2) << std::setfill('0') << vecCh9.at(6)
        << std::setw(2) << std::setfill('0') << vecCh9.at(7)
        << std::setw(2) << std::setfill('0') << vecCh9.at(8)
        << "_" 
        << std::setw(2) << std::setfill('0') << vecCh9.at(9)
        << std::setw(2) << std::setfill('0') << vecCh9.at(10)
        << std::setw(2) << std::setfill('0') << vecCh9.at(11)
        << std::setw(3) << std::setfill('0') << vecCh9.at(12)
        << ".csv";
    std::string csvFileName = oss.str();
    std::string strFileName = createFileName(csvFileName, vecCh9);
    return strFileName;
}

// 解析一个完整的包
int parsePacket(const uint8_t* pkt, size_t len, uint8_t* crcData, int &iCrcDataLen, std::vector<uint16_t> &vecCh9, int iPacketIndex)
{
    // time_t now = time(nullptr);
    // auto timeStart = std::chrono::high_resolution_clock::now();
    if (len != PACKET_SIZE) return -1;
    if (pkt[0] != 0x00) return -2; // 帧序号起始为0x00

    uint16_t dataLen = BytesLeToShort(&pkt[1], 2);
    
    int offset = 0;
    // 第一行
    int iLineSize = 1;
    int allDataSize = 0;
    memcpy(crcData + offset, pkt + offset + 1, 2);
    offset += 2;
    allDataSize = 2;

    memcpy(crcData + offset, pkt + offset + 1, 61 );
    offset += 61;
    allDataSize += 61;
    // 中间行
    int iLiness = (dataLen - 61) / 63; 
    for (size_t i = 1; i <= iLiness; i++) {
        memcpy(crcData + offset, pkt + i*64 + 1, 63);
        offset += 63;
        iLineSize++;
        allDataSize += 63;
    }
    // 最后一行
    size_t remain = dataLen - (61 + 63*iLiness);
    
    memcpy(crcData + offset, pkt + (iLiness + 1)*64 + 1, remain);
    offset += remain;
    allDataSize += remain;

    uint8_t valueA = Data_CRC8(crcData, allDataSize);
    int iPosB = (iLiness + 1)*64 + 1 + remain;
    uint8_t valueB = pkt[(iLiness + 1)*64 + 1 + remain];
    iCSVCont++;
    // std::cout<<"Pack("<<iCSVCont<<") CRC8 valueA:" << std::hex <<static_cast<int>(valueA) << " valueB: " << std::hex <<static_cast<int>(valueB)<<std::dec<<std::endl;
    if (valueA != valueB) {
        std::cerr << "Failed: CRC8 Verify" << std::endl;
        std::cout << "CRC8 Checksum valueA:" << std::hex << static_cast<int>(valueA) << " valueB:" << std::hex << static_cast<int>(valueB) << std::dec << std::endl;
        return -3;
    } else {
        // std::cout << "Successed: CRC8 Verify:"<< std::endl;
    }
    int iDataLen = dataLen - 8 * 512 * sizeof(uint16_t);

    int iResult = parseChannel9Data(vecCh9, crcData + (2 + 8 * 512 * sizeof(uint16_t)), iDataLen);
    int iLen = sizeof(Channel9Data_T);
    // auto timeParsePacket = std::chrono::high_resolution_clock::now();
    // std::cout << "Time parsePacket: " <<std::dec<< std::chrono::duration_cast<std::chrono::microseconds>(timeParsePacket - timeStart).count() << " US" << std::endl;

    std::string  csvFileName;
    // 这种策略, 是将一个Bin文件转换之后, 直接写入一个CSV文件, 而不是每个数据包都创建一个新的CSV文件, 不知道后面还会不会改, 当前先屏蔽保留
    // 记录文件名字
    // if (0 == iPacketIndex)
    {
        // auto now = std::chrono::system_clock::now();
        // auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
        // std::time_t now_c = std::chrono::system_clock::to_time_t(now);
        // std::tm* local_tm = std::localtime(&now_c);
        

        // 输出的CSV文件名命名规则：20210915_123456789_001.csv
    

        // csvFile.open(createFileName(csvFileName, vecCh9), std::ios::out | std::ios::trunc);  // 第一个包清空写
        
        // std::cout << "CSV file Create: " << strFileName3 << std::endl;
        // if (!csvFile.is_open()) {
        //     std::cerr << "CSV file open failed: " << strFileName3 << "\n";
        //     std::cerr << "fail(): " << csvFile.fail()
        //           << " good(): " << csvFile.good()
        //           << " is_open(): " << csvFile.is_open() << std::endl;
        //     return -4;
        // } else {
        //     // std::cout << "CSV file created successed: " << strFileName3 << "\n";
        // }
    } 
    // else {
    //     if (csvFile.is_open())
    //     {
    //         csvFile.close();
    //     }
    //     csvFile.open(csvPath, std::ios::out | std::ios::app);  // 第一个包清空写
    //     std::cout << "append to CSV file: " << csvPath << std::endl;
    //     if (!csvFile) {
    //         std::cerr << "append csv failed: " << csvPath << "\n";
    //         return false;
    //     } else{
    //         std::cout << "append csv successed: " << csvPath << "\n";
    //     }
    // }
    
    // 第一行才会写入表头
    // if (includeHeader && 0 == iPacketIndex) 
    // if (includeHeader) 
    // {
    //     // std::cout << "Write CSV Header..." << std::endl;
    //     for (int i = 0; i < NUM_COLUMNS; i++) {
    //         csvFile << "\"Tunnel-" << i + 1 << "\"";
    //         if (i < NUM_COLUMNS - 1 || CHANNEL9_SIZE > 0) csvFile << ",";
    //     }
    //     csvFile << "\"Tunnel-9\"\n";

    // } else {
    //     // std::cout << "Skip CSV Header..." << std::endl;
    // }

    // // 写入 512 行
    // // 方案一:
    // for (int row = 0; row < 512; row++) {
    //     for (int col = 0; col < 8; col++) {
    //         uint16_t val = u16data[col * 512 + row + 1];
    //         csvFile << val << ",";
    //     }

    //     if (row < vecCh9.size()) 
    //     {
    //         csvFile << vecCh9[row];
    //     } else 
    //     {
    //         csvFile << 0;
    //     }

    //     csvFile << "\n";
    // }
    // csvFile.flush();
    // csvFile.close();

    // auto timeToCSV = std::chrono::high_resolution_clock::now();std::chrono::high_resolution_clock::now();
    // std::cout << "Time WriteToCSV: " <<std::dec<< std::chrono::duration_cast<std::chrono::microseconds>(timeToCSV -timeParsePacket).count() << " MS" << std::endl;
    // // std::cout << "Time WriteToCSV: " <<std::dec<< std::chrono::duration_cast<std::chrono::milliseconds>(timeToCSV -timeParsePacket).count() << " MS" << std::endl;

    // 方案二:
    // std::ostringstream ossCSV;
    // for (int row = 0; row < 512; row++) {
    //     for (int col = 0; col < 8; col++) {
    //         ossCSV << u16data[col * 512 + row + 1] << ",";
    //     }
    //     if (row < vecCh9.size()) {
    //         ossCSV << vecCh9[row];
    //     } else {
    //         ossCSV << "0";
    //     }
    //     ossCSV << "\n";
    // }
    // csvFile << ossCSV.str();
    // csvFile.close();

    // 方案三:
    // char buf[1024];
    // for (int row = 0; row < 512; ++row) {
    //     int len = 0;
    //     for (int col = 0; col < 8; ++col) {
    //         len += snprintf(buf + len, sizeof(buf) - len, "%u,", u16data[col * 512 + row + 1]);
    //     }
    //     len += snprintf(buf + len, sizeof(buf) - len, "%u\n", (row < vecCh9.size()) ? vecCh9[row] : 0);
    //     csvFile.write(buf, len);
    // }
    // csvFile.close();

    return 0;
}



// 修改后的 binToCsvStreaming
int binToCsvStreaming(const std::string& binPath, std::string& csvPath, bool includeHeader) 
{
    std::cout << "Start binToCsvStreaming" << std::endl;
    std::cout.flush();

    ThreadPool pool(1);
    std::vector<std::future<void>> futures;

    if (binPath.empty()) return -1;

    int iGetCSV = 0;
    std::ifstream binFile(binPath, std::ios::binary);
    if (!binFile) {
        std::cerr << "Failed to open bin file: " << binPath << " - Reason: " << std::strerror(errno) << std::endl;
        return -2;
    }

    csvPath = "";
    uint8_t buffer2[PACKET_SIZE * 2] = {0};
    size_t bytesInBuffer = 0;
    size_t pos = 0;
    int iPacketIndex = 0;

    time_t now = time(nullptr);
    auto m_start = std::chrono::high_resolution_clock::now();
    while (true) {
        size_t spaceLeft = sizeof(buffer2) - bytesInBuffer;
        size_t toRead = std::min(PACKET_SIZE, spaceLeft);
        binFile.read(reinterpret_cast<char*>(buffer2 + bytesInBuffer), toRead);
        size_t bytesRead = binFile.gcount();

        if (bytesRead == 0 && bytesInBuffer == 0) break;
        bytesInBuffer += bytesRead;
        if (bytesInBuffer < PACKET_SIZE) break;

        while (pos + 3 <= bytesInBuffer) {
            if (buffer2[pos] == HEADER[0] &&
                buffer2[pos+1] == HEADER[1] &&
                buffer2[pos+2] == HEADER[2])
            {
                int iCrcDataLen = DATA_SIZE + 2;
                uint8_t* crcData = new uint8_t[iCrcDataLen];
                std::vector<uint16_t> vecCh9;

                if (pos + PACKET_SIZE <= bytesInBuffer) {
                    int iResult = parsePacket(buffer2 + pos, PACKET_SIZE, crcData, iCrcDataLen, vecCh9, iPacketIndex);
                    if (iResult == 0) {
                        pos += PACKET_SIZE;
                        iPacketIndex++;
                        auto u16vec = std::make_shared<std::vector<uint16_t>>(DATA_SIZE / 2);
                        memcpy(u16vec->data(), crcData + 2, DATA_SIZE);
                        iGetCSV++;
                        auto vecCh9Copy = std::make_shared<std::vector<uint16_t>>(vecCh9);

                        // 将 push_back 放入 try 块，并打印任务计数
                       // try {
                            auto future = pool.enqueue([u16vec, vecCh9Copy, iGetCSV]() {
                                try {
                                    size_t dataLen = u16vec->size() * sizeof(uint16_t);
                                    int result = writeCSV(u16vec->data(), dataLen, *vecCh9Copy);
                                    if (result != 0) {
                                        std::cerr << "Task " << iGetCSV << " failed in writeCSV "<< std::endl;
                                    }
                                } catch (const std::exception& e) {
                                    std::cerr << "Task " << iGetCSV << " writeCSV exception: " << e.what() << std::endl;
                                } catch (...) {
                                    std::cerr << "Task " << iGetCSV << " writeCSV exception: unknown error" << std::endl;
                                }
                            });
                            futures.push_back(std::move(future));
                            std::cout << "Submitted task " << iGetCSV << ", total tasks: " << futures.size() << std::endl;
                        // } catch (const std::exception& e) {
                        //     std::cerr << "Task " << iGetCSV << " enqueue failed: " << e.what() << std::endl;
                        // }
                    } else if (iResult == -3) {
                        pos++;
                    } else {
                        pos++;
                    }
                } else {
                    size_t remaining = bytesInBuffer - pos;
                    memmove(buffer2, buffer2 + pos, remaining);
                    bytesInBuffer = remaining;
                    pos = 0;
                    break;
                }
                delete[] crcData;
            } else {
                pos++;
            }
        }

        if (pos + 3 > bytesInBuffer) {
            size_t remaining = bytesInBuffer - pos;
            memmove(buffer2, buffer2 + pos, remaining);
            bytesInBuffer = remaining;
            pos = 0;
        }
    }
    auto end = std::chrono::high_resolution_clock::now();
    int iAllTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start).count();
    std::cout << "All Paras Time: " <<std::dec<< std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start).count() << " MS" << std::endl;
    binFile.close();

    std::cout << "Waiting for " << futures.size() << " tasks to complete" << std::endl;
    for (size_t i = 0; i < futures.size(); ++i) {
        try {
            futures[i].get();
            std::cout << "Task " << (i + 1) << " completed" << std::endl;
        } catch (const std::exception& e) {
            std::cerr << "Task " << (i + 1) << " future.get() exception: " << e.what() << std::endl;
        }
    }

    std::cout << "binToCsvStreaming Done\n";
    std::cout.flush();
    return 0;
}
#endif // BIN_TO_CSV_H
